package ms.unicorn.simulation;

import java.util.HashSet;
import java.util.Set;

public class DAT extends HashSet<DAT.AnnotatedAlternative> {

	private static final long serialVersionUID = 1L;

	public static class AnnotatedAlternative extends HashSet<FDNode> implements Comparable<AnnotatedAlternative> {
		private static final long serialVersionUID = 1L;
		//private final Set<FDNode> alternatives;
		private float mb = 0, rr = 0;
		// dummy tail
		
		public AnnotatedAlternative() {
			//alternatives = new HashSet<FDNode>();
		}
		
		public AnnotatedAlternative(Set<FDNode> nodes, float mb, float rr) {
			//alternatives = new HashSet<FDNode>(nodes);
			this.addAll(nodes);
			this.mb = mb;
			this.rr = rr;
		}
		
		public AnnotatedAlternative(FDNode node, float mb, float rr) {
			//alternatives = new HashSet<FDNode>();
			//alternatives.add(node);
			this.add(node);
			this.mb = mb;
			this.rr = rr;
		}

		@Override
		public String toString() {
			String s = "{";
			for (FDNode child: this)
				s += String.format("%s ", child.getName());
			s += "}";
			return s;
		}
		
		public float getMB() {
			return mb;
		}
	
		public void setMB(float mb) {
			this.mb = mb;
		}
	
		public float getRR() {
			return rr;
		}
	
		public void setRR(float rr) {
			this.rr = rr;
		}

		@Override
		public boolean equals(Object obj) {
			/*if (obj instanceof AnnotatedAlternative)
				return alternatives.equals(((AnnotatedAlternative) obj).alternatives);*/
			return super.equals(obj);
		}
		
		@Override
		public int compareTo(AnnotatedAlternative o) {
			/*boolean le = o.alternatives.containsAll(alternatives);
			boolean ge = alternatives.containsAll(o.alternatives);*/
			boolean le = o.containsAll(this);
			boolean ge = containsAll(o);
			if (le)
				if (ge) return 0; else return -1;
			else if (ge) return 1;
			else return 2;
		}
		
		public boolean isGreaterEqual(AnnotatedAlternative o) {
			//return alternatives.containsAll(o.alternatives);
			return containsAll(o);
		}

		public static AnnotatedAlternative join(AnnotatedAlternative a, AnnotatedAlternative b) {
			AnnotatedAlternative c = new AnnotatedAlternative();
			c.addAll(a);
			c.addAll(b);
			c.mb = a.mb * b.mb;
			c.rr = 1 - (1 - a.rr) * (1 - b.rr);
			return c;
		}
	}

	@Override
	public String toString() {
		String s = "[";
		for(AnnotatedAlternative alt: this)
			s += alt.toString() + " ";
		s += "]";
		return s;
	}
	
	public static DAT concat(DAT a, DAT b) {
		if (a == null) return b;
		if (b == null) return a;
		
		DAT result = new DAT();
		result.addAll(a);
		result.addAll(b);
			
		result.filter();
		
		return result;
	}
	
	public static DAT join(DAT a, DAT b) {
		if (a == null) return b;
		if (b == null) return a;
		
		DAT result = new DAT();
		for(AnnotatedAlternative ae: a)
			for (AnnotatedAlternative be: b)
				result.add(AnnotatedAlternative.join(ae,  be));
		result.filter();
		return result;
	}
	
	private void filter() {
		AnnotatedAlternative alts[] = this.toArray(new AnnotatedAlternative[size()]);
		for (int i = 0; i < alts.length - 1; i++) 
			if (contains(alts[i])) 
				for (int j = i+1; j < alts.length; j++) {
					int res = alts[i].compareTo(alts[j]);
					switch(res) {
					case 0: // equal
						System.out.println("Found to equal element!");
					case -1: // less than
						remove(alts[j]);
						break;
					case 1: // greater
						remove(alts[i]);
					default: // not comparable
					}
					if (res == 1) break; //
				}
	}

	public boolean addAlternative(FDNode node, int mb, int rr) {
		AnnotatedAlternative alt = new AnnotatedAlternative(node, mb, rr);
		return add(alt);
	}
}
